#ifndef LOG_LOGGER_H
#define LOG_LOGGER_H

#include "Logstream.h"
#include "utility/Noncopyable.h"


#include <functional>
#include <memory>
/// @brief length{not include '\0'}+1==sizeof(include '\0')

class Logger {
public:
    using OutputFunc = std::function<void(const char *, std::size_t)>;
    using FlushFunc = std::function<void()>;

    enum EnumLogLevel { RAW, FATAL, ERROR, WARN, INFO, DEBUG, VERBOSE };

    static EnumLogLevel LEVEL();
    static void RESET_FLUSH_FUNC();
    static void RESET_OUTPUT_FUNC();
    static void SET_LEVEL(EnumLogLevel l);
    static void SET_FLUSH_FUNC(const FlushFunc &func);
    static void SET_OUTPUT_FUNC(const OutputFunc &func);

    Logger(): _stream{}, _file{""}, _line{0}, _level{RAW} {}
    Logger(const std::string_view &file, int line, EnumLogLevel level, bool err);
    ~Logger();

    Logstream &stream() { return _stream; };
    void set_file(const std::string_view &file) { _file = file; }
    void set_line(int line) { _line = line; }

private:
    NONCOPYABLE(Logger);

    void _log_time();

    Logstream _stream;
    std::string_view _file;
    int _line;
    const EnumLogLevel _level;

};


// do not use in if...else... without {}

#define LOG_RAW                         \
    if (Logger::LEVEL() == Logger::RAW) \
    (Logger().stream())
#define LOG_SYSFATAL                    \
    if (Logger::LEVEL() != Logger::RAW) \
    (Logger(__FILE__, __LINE__, Logger::FATAL, true).stream())
#define LOG_SYSERROR                    \
    if (Logger::LEVEL() != Logger::RAW) \
    (Logger(__FILE__, __LINE__, Logger::ERROR, true).stream())
#define LOG_FATAL                       \
    if (Logger::LEVEL() != Logger::RAW) \
    (Logger(__FILE__, __LINE__, Logger::FATAL, false).stream())
#define LOG_ERROR                       \
    if (Logger::LEVEL() != Logger::RAW) \
    (Logger(__FILE__, __LINE__, Logger::ERROR, false).stream())
#define LOG_WARN                        \
    if (Logger::LEVEL() != Logger::RAW) \
    (Logger(__FILE__, __LINE__, Logger::WARN, false).stream())
#define LOG_INFO                         \
    if (Logger::LEVEL() >= Logger::INFO) \
    (Logger(__FILE__, __LINE__, Logger::INFO, false).stream())
#define LOG_DEBUG                                                \
    if (Logger::LEVEL() >= Logger::DEBUG)                        \
    ((Logger(__FILE__, __LINE__, Logger::DEBUG, false).stream()) \
     << __func__ << "(): ")
#define LOG_VERBOSE                                                \
    if (Logger::LEVEL() >= Logger::VERBOSE)                        \
    ((Logger(__FILE__, __LINE__, Logger::VERBOSE, false).stream()) \
     << __func__ << "(): ")

#endif